#ifndef __MY_JSON_H
#define __MY_JSON_H

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <list>
#include <map>
#include <iomanip>


/**
 * @brief 自定义Json
 * 
 */
struct Json
{
    /**
     * 
    */
    enum elem_t
    {
        JNUM_t,    // double*
        JSTRING_t, // string*
        JBOOL_t,   // int *
        JNULL_t,    // null
        JARRAY_t,  // vector<Json*>*
        JOBJECT_t  // map<string, Json*>*
    };

    int type;   // 数据 *addr的类型
    void *addr; // 实际数据的地址

    /**
     * @brief 无参构造
     * 
     */
    Json();
    Json(int val);
    Json(double val);
    Json(bool val); 
    Json(std::string str);
    Json(const char *str);
    Json(elem_t t)
    {
        type = t;
        addr = 0;
    }
    ~Json();

    /**
     * @brief 转为字符串
     * 
     * @return std::string 
     */
    std::string to_string();

    /**
     * @brief 字符串转为Json
     * 
     * @param s 字符串
     * @return Json* 指向创建的Json的指针
     */
    static Json* parse_string(std::string &s);
};

/**
 * @brief Json数组，类型是type = JARRAY_t;
 * 
 */
struct Json_Array : public Json
{

    Json_Array()
    {
        type = JARRAY_t;
        auto arr = new std::vector<Json *>;
        addr = arr;
    }
    constexpr std::vector<Json *> &get_arr()
    {
        return *(std::vector<Json *> *)(addr);
    }
    /**
     * @brief 添加Json元素
     * 
     * @param js Json指针
     */
    void add(Json *js)
    {
        auto &arr = get_arr();
        arr.push_back(js);
    }
    size_t size(){
        return get_arr().size();
    }
    bool empty(){
        return get_arr().empty();
    }
};

/**
 * @brief Json对象 继承自Json类，type = JOBJECT_t;
 * 
 */
struct Json_Object : public Json
{

    Json_Object()
    {
        type = JOBJECT_t;
        auto mp = new std::map<std::string, Json *>;
        addr = mp;
    }
    std::map<std::string, Json *> &get_map()
    {
        return *(std::map<std::string, Json *> *)(addr);
    }
    void insert(const std::string &key, Json *js)
    {
        auto &arr = get_map();
        arr.insert({key, js});
    }
    size_t size(){
        return get_map().size();
    }
    bool empty(){
        return get_map().empty();
    }
};
#endif 
